/**
  ******************************************************************************
  * @file 
  * @brief 设备监控任务（设备计时、压力传感器）
  * @author zp
  * @version V1.0.0
  * @date 2024/02/20
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "system.h"
#include "FreeRTOS.h"
#include "task.h"
#include "step_motor.h"
#include "A_shell.h"
#include "main_task.h"
#include "task.h"
#include "dev_ad7193_temp.h"
#include "dev_ad7193_press.h"	
#include "step_motor.h"
#include "ParmManage.h"
#include "cmd_process.h"
#include "lwip_app.h"
/* Private defines -----------------------------------------------------------*/
#define	LOG_PRINT_TIME	1000	    //log打印周期1秒
#define	GLP_TIME     	3000000	    //设备计时周期20毫秒,
#define	PUMP_TIME     	3000000	    //设备计时周期20毫秒,单位1min

#define	PRESS_RELIEF_THREHOLD    	(1200 * 133.322)	    //泄压阈值
#define	PRESS_RELIEF_STOP_VALUE    	(760 * 133.322)	    //泄压阈值

//传感器采集完成标记
#define SENSOR_TEMP_COMPLETE        (1 << 0)
#define PRE_SENSOR_S1_COMPLETE      (1 << 1)
#define PRE_SENSOR_S2_COMPLETE      (1 << 2)
#define PRE_SENSOR_S3_COMPLETE      (1 << 3)
#define PRE_SENSOR_P0_COMPLETE      (1 << 4)
#define PRE_SENSOR_BASE_COMPLETE    (1 << 5)


// 所有传感器采集完成的位掩码
#define ALL_SENSORS_COMPLETED (SENSOR_TEMP_COMPLETE | PRE_SENSOR_S1_COMPLETE | \
                              PRE_SENSOR_S2_COMPLETE | PRE_SENSOR_S3_COMPLETE | \
                              PRE_SENSOR_P0_COMPLETE | PRE_SENSOR_BASE_COMPLETE)

#define TEMP_READ   (0)
#define PRESS_READ  (1)

#define GET_INIT_MOTOR_STATE() do { \
    uint8_t motor_st = 0x0; \
    if(0 == step1_limit_io_read(FORWARD_LIMITE)) /* 电机正传上限位 */ \
    { \
        motor_st = 0x03; \
    } \
    else if(0 == step1_limit_io_read(REVERSE_LIMITE)) /* 电机反转下限位 */ \
    { \
        motor_st = 0x04; \
    } \
    data_server.motor.st = motor_st; \
} while(0)

/* Public Var  -----------------------------------------------------------*/
extern struct Socket_Struct WorkSocket[2];
extern  SemaphoreHandle_t xSemaphore_limit;
extern SemaphoreHandle_t xNotifyReadBasePressSemaphore;
extern RunStateMachine_e rsm;
extern volatile bool detectDataReady;
//extern TaskHandle_t MonitorTask_Handler; 
extern QueueHandle_t xMonitorQueue;
extern SensorCalibration calibrations[6];
extern uint8_t signal;
extern uint8_t temp_complete_flag;
extern uint8_t valve_flag;
/* Private Struct  -----------------------------------------------------------*/

typedef struct
{
    uint8_t type;         // 0 for adc7193_temp.Read, 1 for adc7193_press.Read
    uint8_t channel;      // AD7193 channel
    uint8_t calibration_idx;          // Calibration index
    uint8_t sensor_idx;   // Index in the current_press array
} SensorMapping;

//建立传感器序号对应关系，简化冗余代码
SensorMapping sensorMapping[(PRE_SENSOR_MAX + 1) * 2 + 1];

/* Private enum    -----------------------------------------------------------*/

/* Private Variable  ---------------------------------------------------------*/

static bool mon_log_switch = false;
bool mon_pumpTim_switch = false;
uint32_t g_pumpCnt = 0;
uint64_t g_glpCnt = 0;

SampleStateMachine_e ssm = SSM_TEMP;

SemaphoreHandle_t xGetPressMutex;
SemaphoreHandle_t xMonitorDataReadySem;
EventGroupHandle_t xSensorEventGroup;
QueueHandle_t MonitorDataQueue;

float buffer[PRE_SENSOR_MAX + 1];
static float *MonitorCurrentBuffer;
//Array

//Const


/***********************************************************************************
 * @brief log打印函数	
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static void mon_log_print(uint32_t timebase)
{
	static uint32_t logTime = 0;

	if (mon_log_switch == false)
		return;
	
	logTime += timebase;
	if ((logTime % LOG_PRINT_TIME) != 0)
		return;
//	Ashell_print("P_sensor1 = %f, P_sensor2 = %f, T_sensor1 = %f, T_sensor2 = %f\r\n",
//				 pBody.P_sensor1, pBody.P_sensor2, pBody.T_sensor1, pBody.T_sensor2);
//	Ashell_print("P_sensor1 = %f, P_sensor2 = %f, T_sensor1 = %f, T_sensor2 = %f\r\n",
//				 pS1.P_sensor1, pS1.P_sensor2, pS1.T_sensor1, pS1.T_sensor2);
//	Ashell_print("P_sensor1 = %f, P_sensor2 = %f, T_sensor1 = %f, T_sensor2 = %f\r\n",
//				 pS2.P_sensor1, pS2.P_sensor2, pS2.T_sensor1, pS2.T_sensor2);
//	Ashell_print("P_sensor1 = %f, P_sensor2 = %f, T_sensor1 = %f, T_sensor2 = %f\r\n",
//				 pS3.P_sensor1, pS3.P_sensor2, pS3.T_sensor1, pS3.T_sensor2);
}

/***********************************************************************************
 * @brief 设备计时函数	
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static void mon_glp(uint32_t timebase)
{
	static uint32_t glpTime = 0, pumpTime = 0;
	
	glpTime += timebase;  //单位
	if ((glpTime % GLP_TIME) != 0)
		return;
	
	g_glpCnt++; 
}

/***********************************************************************************
 * @brief 设备计时函数	
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static void mon_pumptime(uint32_t timebase)
{
	static uint32_t pumpTime = 0;
	
	if (mon_pumpTim_switch == false)
		return;
	
	pumpTime += timebase;
	if ((pumpTime % PUMP_TIME) != 0)
		return;
	
	g_pumpCnt++;
}


void InitSensorMapping(void)
{
        SensorMapping configs[] = 
        {
            {PRESS_READ, AD7193_CH2, 0, PRE_SENSOR_S1},
            {PRESS_READ, AD7193_CH1, 1, PRE_SENSOR_S2},
            {PRESS_READ, AD7193_CH3, 2, PRE_SENSOR_S3},
            {PRESS_READ, AD7193_CH4, 3, PRE_SENSOR_P0},
            {PRESS_READ, AD7193_CH0, 4, PRE_SENSOR_BASE},
            
            {TEMP_READ, AD7193_CH0, 5, PRE_SENSOR_MAX},
            {TEMP_READ, AD7193_CH3, 6, PRE_SENSOR_S1},
            {TEMP_READ, AD7193_CH4, 7, PRE_SENSOR_S2},
            {TEMP_READ, AD7193_CH5, 8, PRE_SENSOR_S3},
            {TEMP_READ, AD7193_CH6, 9, PRE_SENSOR_P0},
            {TEMP_READ, AD7193_CH7, 10, PRE_SENSOR_BASE},
            {TEMP_READ, AD7193_CH8, 11, PRE_SENSOR_MAX},
            
            //DAC反馈通道
            {PRESS_READ, AD7193_CH5, 4, PRE_SENSOR_BASE},
            

        };

        int configCount = sizeof(configs) / sizeof(configs[0]);
        for (int i = 0; i < configCount; i++) 
        {
            sensorMapping[i].type = configs[i].type;
            sensorMapping[i].channel = configs[i].channel;
            sensorMapping[i].calibration_idx = configs[i].calibration_idx;
            sensorMapping[i].sensor_idx = configs[i].sensor_idx;
        }
}
/***********************************************************************************
 * @brief 设备状态监测
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static void monitor_pack(void)
{	
	timeval_t tv;    //读取系统时钟
    static int s_first_in = 1;
    //pack
	data_server.monitor_pack_u.arr.press[0] = data_server.press_par.current_press[0];
	data_server.monitor_pack_u.arr.press[1] = data_server.press_par.current_press[1];
	data_server.monitor_pack_u.arr.press[2] = data_server.press_par.current_press[2];
	data_server.monitor_pack_u.arr.press[3] = data_server.press_par.current_press[3];
	data_server.monitor_pack_u.arr.press[4] = data_server.press_par.current_press[4];
	
	data_server.monitor_pack_u.arr.temp = data_server.temp;
	data_server.monitor_pack_u.arr.valve = data_server.valve.cmd;
	data_server.monitor_pack_u.arr.motor_st = data_server.motor.st;
	data_server.monitor_pack_u.arr.dev_time = data_server.tv.second;
	data_server.monitor_pack_u.arr.try_st = 0;
	data_server.monitor_pack_u.arr.excp = 0;
	data_server.monitor_pack_u.arr.proval_open = data_server.ctrl_par.tb[0];
	data_server.monitor_pack_u.arr.proval_state = data_server.press_par.act_final;
	data_server.monitor_pack_u.arr.proval_press_target = (data_server.press_par.act_final == ACTION_NONE ? 0 : data_server.press_par.target_press_final);
	data_server.monitor_pack_u.arr.gas_type = data_server.gas_type;
    
	//dev_time.time(&dev_time,&tv);
    //data_server.monitor_pack_u.arr.msecond = tv.msecond;    //时钟Tick ms计数值
	
    if(valve_flag)
	{
		uint16_t valve_st = 0;
		valve_st = data_server.valve.cmd;
		
		Aclass_Protocol_Send("valve", &valve_st, sizeof(uint16_t)); 
		valve_flag = 0;
	}
	
	if(temp_complete_flag)
	{
		uint8_t cali_completed = 0;
		Aclass_Protocol_Send("complete_temp_cali", &cali_completed, sizeof(uint8_t)); 
		temp_complete_flag = 0;
	}
    
   
	Aclass_Protocol_Send("monitor", data_server.monitor_pack_u.buf, sizeof(data_server.monitor_pack_u));

    if(s_first_in == 1 ||  data_server.isBaseVolChanged == true || (WorkSocket[0].connect_flag == true && WorkSocket[0].last_connect_flag == false)) 
    {   
        s_first_in = 0;
        if(WorkSocket[0].connect_flag == true && WorkSocket[0].last_connect_flag  == false)
        {
            WorkSocket[0].last_connect_flag = true;
        }
        PPItemRead(PP_BASE_CBM, (uint8_t *)(&data_server.base_volume), 4);
        Aclass_Protocol_Send("upload_base_cbm", &data_server.base_volume, sizeof(float));
        Ashell_print("data_server.base_volume is %f cm3 \r\n",data_server.base_volume);      
    }
    
}

/**************************************************************/
/*功能说明：检查步进电机是否到达上下限位
* 输入参数：无
* 输出参数：无
* 返回值：无
*/
/**************************************************************/
static void monitor_stepmotor_location(void)
{
	uint8_t motor_st = 0x0;
    if(0 == step1_limit_io_read(FORWARD_LIMITE))        //电机正传上限位
	{
		motor_st = 0x03;
		
	}
	else if(0 == step1_limit_io_read(REVERSE_LIMITE))   //电机反转下限位
	{
		motor_st = 0x04;
	}
    data_server.motor.st = motor_st;
    Ashell_print("notify motor state:%d\r\n",motor_st); 
    Aclass_Protocol_Send("motor", &motor_st, sizeof(uint8_t)); 
	
}

/*---------------------------------------------------------------------------------------
 函数原型:  static void IsPresOver(void)
 功    能: 判断压力传感器超过阈值
 输入参数:	NA
 输出参数:	NA
 返 回 值:	压力超阈值的压力传感器掩码值
 注意事项：	
----------------------------------------------------------------------------------------*/
static uint8_t WhichPressSenor_OverThrehold(void)
{

    uint8_t sensorMask = 0;
    for (int i = 0;i < PRE_SENSOR_MAX;i++)
    {
        if(data_server.press_par.current_press[i] > PRESS_RELIEF_THREHOLD)
			sensorMask |= 1 << i;
    }
    return sensorMask;
}

/*---------------------------------------------------------------------------------------
 函数原型:  static void IsPresOver(void)
 功    能: 判断压力传感器值是否在760mmHg附近
 输入参数:	uint8_t overSensorMask - 压力超阈值的腔体标志位
 输出参数:	无
返 回 值:	超阈值的压力传感器掩码值
 注意事项：	
----------------------------------------------------------------------------------------*/
static uint8_t WhichPressSenor_760mmHG(uint8_t overSensorMask)
{

    uint8_t sensorMask = 0x1f;

    
    for (int i = 0;i < PRE_SENSOR_MAX;i++)
    {
        if((overSensorMask) & (1 << i))
        {
           if(data_server.press_par.current_press[i] < PRESS_RELIEF_STOP_VALUE + 5 * 133.322)
           {
               sensorMask &= ~(1 << i);
           }
        } 
			
    }
    return sensorMask;
}

/*---------------------------------------------------------------------------------------
 函数原型:  static void IsPresOver(void)
 功    能:  压力超过阈值处理
 输入参数:	NA
 输出参数:	NA
 返 回 值:	NA
 注意事项：	
----------------------------------------------------------------------------------------*/
static void IsPresOver(void)
{ 
    uint8_t sensorMask = 0;
    uint8_t sensorMask_760mmHg = 0;
	
    vTaskDelay( pdMS_TO_TICKS(100));
    sensorMask = WhichPressSenor_OverThrehold();
	
    if(sensorMask)
    {
        data_server.valve_resetall(&data_server);
        //存在压力传感器的值超过阈值    
        data_server.valve_localset(&data_server, (uint8_t)VALVE_PRO_PUMP, 1);

        //开启具体压力传感器对应的阀
        if(sensorMask & (1<<0))
        {
            data_server.valve_localset(&data_server, (uint8_t)VALVE_S1_PUMP, 1);
        }
        if(sensorMask & (1<<1))
        {
            data_server.valve_localset(&data_server, (uint8_t)VALVE_S2_PUMP, 1);    
        }
        if(sensorMask & (1<<2))
        {        
            data_server.valve_localset(&data_server, (uint8_t)VALVE_S3_PUMP, 1);            
        }
        if(sensorMask & (1<<3))
        {
            data_server.valve_localset(&data_server, (uint8_t)VALVE_P0, 1);        
        }
        if(sensorMask & (1<<4))
        {
            data_server.valve_localset(&data_server, (uint8_t)VALVE_QUICK_PUMP, 1);        
        }
        
         vTaskDelay(pdMS_TO_TICKS(100)); 
        data_server.valve_resetall(&data_server);
//		Ashell_print("valve state:%x\r\n",data_server.valve.cmd );
    }

	
	
    //判断压力是否下降到760mmHg
//    while(sensorMask)
//    {
//		data_server.press_par.current_press[0] = adc7193_press.Read_InfPump(&adc7193_press, AD7193_CH2, 1) * calibrations[0].slope + calibrations[0].intercept;
//		data_server.press_par.current_press[1] = adc7193_press.Read_InfPump(&adc7193_press, AD7193_CH1, 1) * calibrations[1].slope + calibrations[1].intercept;
//		data_server.press_par.current_press[2] = adc7193_press.Read_InfPump(&adc7193_press, AD7193_CH3, 1) * calibrations[2].slope + calibrations[2].intercept;
//		data_server.press_par.current_press[3] = adc7193_press.Read_InfPump(&adc7193_press, AD7193_CH4, 1) * calibrations[3].slope + calibrations[3].intercept;   
//		data_server.press_par.current_press[4] = adc7193_press.Read_InfPump(&adc7193_press, AD7193_CH0, 1) * calibrations[4].slope + calibrations[4].intercept; 

//        //判断压力是否降到760mmHg
//        sensorMask_760mmHg = WhichPressSenor_760mmHG(sensorMask);
//        if(!(sensorMask_760mmHg & sensorMask))
//        {
//            data_server.valve_localset(&data_server, (uint8_t)VALVE_PRO_PUMP, 0);
//            data_server.valve_localset(&data_server, (uint8_t)VALVE_S1_PUMP, 0);
//            data_server.valve_localset(&data_server, (uint8_t)VALVE_S2_PUMP, 0);  
//            data_server.valve_localset(&data_server, (uint8_t)VALVE_S3_PUMP, 0);  
//            data_server.valve_localset(&data_server, (uint8_t)VALVE_P0, 0); 
//            data_server.valve_localset(&data_server, (uint8_t)VALVE_QUICK_PUMP, 0);
//            sensorMask = 0;
//        }
//    }

}
/***********************************************************************************
 * @brief 数据采集任务
 * ex:
 * @par
 * None
 * @retval
 **********************************************************************************/
float monitor_voltage[6] = {0};  
void MonitorDataCollectTask(void *pvParameters) 
{		
    //加载压力传感器和温度传感器的k、b值
	GET_INIT_MOTOR_STATE();
    read_all_sensors_calibration();
	read_tempsensors_calibration();	
	InitSensorMapping();
	
	//初始化缓冲区指针
    MonitorCurrentBuffer = buffer;

//    TickType_t lastUploadTick = 0;  // 上次上传的滴答数
//    TickType_t currentTick;
//    TickType_t uploadInterval;
    
	
    while (1) 
    {
        // 采集数据
        //currentTick = xTaskGetTickCount();

        for (int i = 0; i < 2 * (PRE_SENSOR_MAX + 1) + 1; i++) 
        {
            if (sensorMapping[i].type == TEMP_READ) 
            {
                if(i == PRE_SENSOR_MAX)
                {
                    //Ashell_print("cap temp\r\n");
                    data_server.lastTemp = adc7193_temp.Read_Balance(&adc7193_temp, sensorMapping[i].channel, 1);
                    MonitorCurrentBuffer[sensorMapping[i].sensor_idx] = data_server.lastTemp + calibrations[sensorMapping[i].sensor_idx].intercept;
                    //Ashell_print("after cap temp,get temp:%f\r\n",MonitorCurrentBuffer[sensorMapping[i].sensor_idx]);
                }		
//                else
//                {
//                    monitor_voltage[i] = adc7193_temp.Read_Voltage(&adc7193_temp, sensorMapping[i].channel, 1);
//                    //Ashell_print("ch %d voltage is %f\r\n",sensorMapping[i].channel,monitor_voltage[i]);
//                } 
            } 
            else if (sensorMapping[i].type == PRESS_READ) 
            {
                if(sensorMapping[i].channel != AD7193_CH5)
                {
                    MonitorCurrentBuffer[sensorMapping[i].sensor_idx] = adc7193_press.Read_Balance(&adc7193_press, sensorMapping[i].channel, 1) * calibrations[sensorMapping[i].sensor_idx].slope +  calibrations[sensorMapping[i].sensor_idx].intercept;
                
                }
                else
                {
            
                    adc7193_press.Read_Balance(&adc7193_press, AD7193_CH5, 1);                          
                }
            
            }

            // 根据传感器索引设置相应的事件位
            //Ashell_print("Sensor %d data collected, setting event bit\r\n", i);
            xEventGroupSetBits(xSensorEventGroup, (1 << i));

        }

    //uploadInterval = xTaskGetTickCount() - currentTick;
    //Ashell_print("time gap:%d\r\n",uploadInterval);
    xEventGroupSetBits(xSensorEventGroup, ALL_SENSORS_COMPLETED);
    
    //更新电机位置
    if(xSemaphoreTake(xSemaphore_limit, pdMS_TO_TICKS(10)) == pdTRUE) 
    {
        monitor_stepmotor_location();
    }    
    
    //更新基体腔压力值
    if (xSemaphoreTake(xNotifyReadBasePressSemaphore, pdMS_TO_TICKS(10)) == pdTRUE) 
    {
        data_server.press_par.current_press[PRE_SENSOR_BASE] = adc7193_press.Read_Balance(&adc7193_press, AD7193_CH0, 1) * calibrations[4].slope + calibrations[4].intercept;
        Ashell_print("get cur press value:%f mmHg\r\n", data_server.press_par.current_press[4]/133.322);
    }
        
    vTaskDelay(pdMS_TO_TICKS(100)); 
    }
}

/***********************************************************************************
* @brief 数据上传任务
 * ex:
 * @par
 * None
 * @retval
 **********************************************************************************/
void MonitorDataUploadTask(void *pvParameters) 
{
    EventBits_t uxBits;

    TickType_t lastUploadTick = 0;  // 上次上传的滴答数
    TickType_t currentTick;
    TickType_t uploadInterval;

    while (1) 
    {
					
        currentTick = xTaskGetTickCount();
        if (lastUploadTick != 0)
        {
            uploadInterval = currentTick - lastUploadTick;
        }
			
        // 等待任何一个传感器采集完成，或超时100ms
        uxBits = xEventGroupWaitBits(xSensorEventGroup, 
                                     ALL_SENSORS_COMPLETED,  // 等待所有传感器的事件位
                                     pdTRUE,           // 清除事件位
                                     pdFALSE,          // 等待任意一个传感器完成
                                     pdMS_TO_TICKS(100));  

        //Ashell_print("Uploaded data after waiting for events. Current status: 0x%X\r\n", uxBits); 
        // 检查是否有传感器完成数据采集
        if (uxBits != 0) 
        {
            //Ashell_print("uxBits:%x\r\n", uxBits);
            for (int i = 0; i < PRE_SENSOR_MAX + 1; i++) 
            {
                // 如果该传感器已完成数据采集
                if ((uxBits & (1 << i))  && i != PRE_SENSOR_MAX)
                {
                    data_server.press_par.current_press[i] = MonitorCurrentBuffer[i];
                }
                else if ((uxBits & (1 << i))  && i == PRE_SENSOR_MAX)
                {
                    data_server.temp = MonitorCurrentBuffer[i];
                }
            }
        }
        
        // 检查是否所有传感器都完成了数据采集
        monitor_pack();  
        //Ashell_print("temp:%f\r\n",data_server.temp);
       
        lastUploadTick = currentTick;
	
        //过压检测及执行
		IsPresOver();
        
        // 每500ms上传一次（若无新数据则重复上传上次数据）
        vTaskDelay(pdMS_TO_TICKS(50));
    }
}


/***********************************************************************************
 * @brief 功能说明：监测信息测试接口
 * ex:
 * @par   输入参数：
 *                  
 * @retval返回值：无
 **********************************************************************************/
static int monitor_info(uint8_t argc, char **argv)
{
    if (argc >= 2){
        if (!strcmp(argv[1], "log")){
            if (argc >= 3){
                if (!strcmp(argv[2], "open"))
                    mon_log_switch = true;
                else if (!strcmp(argv[2], "close"))
                    mon_log_switch = false;
            }
            else
            {
                Ashell_print("Please input monitor <log (open, close)>.\r\n");
            }
        }
    }
    else
    {
        Ashell_print("Please input monitor <log (open, close)>.\r\n");
    }
    return 1;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), monitor, monitor_info, monitor_info operation);

/******************* (C) COPYRIGHT 2022 CIQTEK luffy *****END OF FILE****/
